package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"sort"
	"strconv"
	"strings"

	"game-simple/internal/infrastructure/config"
	"game-simple/internal/infrastructure/core"
	"game-simple/internal/infrastructure/database"
	"game-simple/internal/infrastructure/logger"
	"game-simple/internal/infrastructure/redis"

	"gorm.io/gorm"
)

func main() {
	configPath := flag.String("config", "cmd/web/config.yaml", "配置文件路径")
	command := flag.String("cmd", "", "迁移命令: up(执行迁移), status(查看状态), rollback(回滚), create(创建迁移), generate(从模型生成SQL), diff(对比表结构生成ALTER)")
	version := flag.String("version", "", "回滚的版本号（rollback 命令需要）")
	name := flag.String("name", "", "迁移文件名称（create/generate/diff 命令需要）")
	model := flag.String("model", "", "模型名称（generate/diff 命令需要，如: UserModel）")
	flag.Parse()

	// 如果没有指定命令，检查是否有位置参数
	if *command == "" {
		args := flag.Args()
		if len(args) > 0 {
			*command = args[0]
			if *command == "create" && len(args) > 1 {
				*name = args[1]
			}
		}
	}

	// help、create、list 和 generate 命令不需要初始化数据库
	if *command == "help" || *command == "" {
		showHelp()
		return
	}

	if *command == "create" {
		if *name == "" {
			// 尝试从位置参数获取
			args := flag.Args()
			if len(args) > 1 {
				*name = args[1]
			} else {
				log.Fatal("创建迁移需要指定名称\n使用方法:\n  go run cmd/migrate/main.go create <迁移名称或模型名>\n例如: go run cmd/migrate/main.go create add_user_avatar\n或: go run cmd/migrate/main.go create UserModel")
			}
		}
		createMigrationFileSmart(*name)
		return
	}

	if *command == "list" {
		initModels()
		listAllModels()
		return
	}

	if *command == "status" {
		// status 命令可以在没有数据库连接时显示迁移文件列表
		showStatusWithoutDB(*configPath)
		return
	}

	if *command == "generate" {
		if *model == "" {
			// 尝试从位置参数获取
			args := flag.Args()
			if len(args) > 1 {
				*model = args[1]
			} else {
				log.Fatal("生成 SQL 需要指定模型名称\n使用方法:\n  go run cmd/migrate/main.go generate <模型名称>\n例如: go run cmd/migrate/main.go generate UserModel")
			}
		}
		generateSQLFromModel(*model, *name)
		return
	}

	if *command == "diff" {
		if *model == "" {
			// 尝试从位置参数获取
			args := flag.Args()
			if len(args) > 1 {
				*model = args[1]
			} else {
				log.Fatal("对比表结构需要指定模型名称\n使用方法:\n  go run cmd/migrate/main.go diff <模型名称>\n例如: go run cmd/migrate/main.go diff UserModel")
			}
		}
		generateDiffFromModel(*model, *name)
		return
	}

	if *command == "seed" {
		// 初始化种子数据（编号规则等）
		seedSequenceRules(*configPath)
		return
	}

	if *command == "list" {
		initModels()
		listAllModels()
		return
	}

	// 其他命令需要加载配置和初始化数据库
	if err := config.LoadConfig(*configPath); err != nil {
		log.Fatalf("加载配置失败: %v", err)
	}

	// 对于迁移命令，只需要初始化数据库，Redis 和 Logger 可选
	// 初始化数据库
	if err := database.InitMySQL(); err != nil {
		log.Fatalf("数据库初始化失败: %v", err)
	}

	// 尝试初始化 Redis（失败不影响迁移操作）
	if err := redis.InitRedis(); err != nil {
		fmt.Printf("⚠️  Redis 初始化失败（不影响迁移操作）: %v\n", err)
	}

	// 尝试初始化日志（失败不影响迁移操作）
	if err := logger.InitLogger(); err != nil {
		fmt.Printf("⚠️  日志初始化失败（不影响迁移操作）: %v\n", err)
	}

	// 创建基础设施实例（用于日志输出）
	infra := &core.Infrastructure{
		DB:     database.NewDB(),
		Cache:  redis.NewCache(),
		Logger: logger.NewLogger(),
	}
	defer func() {
		// 清理数据库连接
		if db := database.GetDB(); db != nil {
			if sqlDB, err := db.DB(); err == nil {
				sqlDB.Close()
			}
		}
	}()

	switch *command {
	case "up":
		infra.Logger.Info("开始执行数据库迁移...")
		if err := database.RunMigrations(); err != nil {
			infra.Logger.Errorf("迁移失败: %v", err)
			log.Fatalf("迁移失败: %v", err)
		}
		infra.Logger.Info("数据库迁移完成")

	case "status":
		status, err := database.GetMigrationStatus()
		if err != nil {
			infra.Logger.Errorf("获取迁移状态失败: %v", err)
			log.Fatalf("获取迁移状态失败: %v", err)
		}

		fmt.Println("\n迁移状态:")
		fmt.Println("版本号\t\t名称\t\t\t状态\t\t应用时间")
		fmt.Println("------------------------------------------------------------")
		for _, s := range status {
			statusStr := "未执行"
			if s.Applied {
				statusStr = "已执行"
			}
			fmt.Printf("%s\t\t%s\t\t%s\t\t%s\n", s.Version, s.Name, statusStr, s.AppliedAt)
		}

	case "rollback":
		if *version == "" {
			log.Fatal("回滚需要指定版本号\n使用方法:\n  go run cmd/migrate/main.go rollback -version=001 -config=cmd/web/config.yaml")
		}
		infra.Logger.Infof("开始回滚迁移版本: %s", *version)
		if err := database.RollbackMigration(*version); err != nil {
			infra.Logger.Errorf("回滚失败: %v", err)
			log.Fatalf("回滚失败: %v", err)
		}
		infra.Logger.Infof("迁移版本 %s 回滚成功", *version)

	default:
		showHelp()
		os.Exit(1)
	}
}

// showHelp 显示帮助信息
func showHelp() {
	// 初始化模型列表
	initModels()

	fmt.Println("数据库迁移工具")
	fmt.Println("\n可用命令:")
	fmt.Println("  up                    - 执行所有待执行的迁移")
	fmt.Println("  status                - 查看迁移状态")
	fmt.Println("  rollback -version=xxx  - 回滚指定版本的迁移")
	fmt.Println("  create <名称/模型>      - 智能创建迁移文件（自动识别模型并选择 generate/diff）")
	fmt.Println("  generate <模型>         - 从 GORM 模型自动生成 CREATE TABLE SQL")
	fmt.Println("  diff <模型>             - 对比现有表结构生成 ALTER TABLE SQL")
	fmt.Println("  list                   - 列出所有可用的模型")
	fmt.Println("\n示例:")
	fmt.Println("  # 创建迁移文件")
	fmt.Println("  # 方式1: 创建空白迁移文件")
	fmt.Println("  go run cmd/migrate/main.go create add_user_avatar")
	fmt.Println("  # 或使用 Makefile: make migrate-create NAME=add_user_avatar")
	fmt.Println("\n  # 方式2: 基于模型自动生成（推荐！）")
	fmt.Println("  go run cmd/migrate/main.go create UserModel")
	fmt.Println("  # 或使用 Makefile: make migrate-create NAME=UserModel")
	fmt.Println("  # 系统会自动:")
	fmt.Println("  #   - 如果表不存在 → 生成 CREATE TABLE SQL")
	fmt.Println("  #   - 如果表已存在 → 生成 ALTER TABLE SQL（包含字段重命名、类型转换、外键等）")
	fmt.Println("\n  # 执行迁移")
	fmt.Println("  go run cmd/migrate/main.go up -config=cmd/web/config.yaml")
	fmt.Println("  # 或使用 Makefile")
	fmt.Println("  make migrate")
	fmt.Println("\n  # 查看迁移状态")
	fmt.Println("  go run cmd/migrate/main.go status -config=cmd/web/config.yaml")
	fmt.Println("  # 或使用 Makefile")
	fmt.Println("  make migrate-status")
	fmt.Println("\n  # 回滚迁移")
	fmt.Println("  go run cmd/migrate/main.go rollback -version=002 -config=cmd/web/config.yaml")
	fmt.Println("  # 或使用 Makefile")
	fmt.Println("  make migrate-rollback VERSION=002")
	fmt.Println("\n  # 从模型生成 SQL（自动生成 CREATE TABLE，表不存在时使用）")
	fmt.Println("  go run cmd/migrate/main.go generate UserModel")
	fmt.Println("  # 或指定迁移名称")
	fmt.Println("  go run cmd/migrate/main.go generate UserModel -name=create_users_table")
	fmt.Println("\n  # 对比表结构生成 ALTER TABLE（表已存在，修改字段时使用）")
	fmt.Println("  go run cmd/migrate/main.go diff UserModel")
	fmt.Println("  # 或指定迁移名称")
	fmt.Println("  go run cmd/migrate/main.go diff UserModel -name=alter_users_add_avatar")
}

// createMigrationFileSmart 智能创建迁移文件（自动识别模型并选择 generate/diff）
func createMigrationFileSmart(name string) {
	// 首先初始化模型列表
	initModels()

	// 检查 name 是否是模型名
	model, isModel := modelRegistry[name]
	if !isModel {
		// 尝试使用完整名称（如 auth.UserModel）
		for key, val := range modelRegistry {
			if strings.HasSuffix(key, name) || strings.EqualFold(key, name) {
				model = val
				isModel = true
				name = key // 使用完整名称
				break
			}
		}
	}

	if !isModel {
		// 不是模型名，创建空白迁移文件
		fmt.Printf("📝 创建空白迁移文件: %s\n", name)
		createMigrationFile(name)
		return
	}

	// 是模型名，需要检查表是否存在
	fmt.Printf("🔍 检测到模型名: %s，正在检查表是否存在...\n", name)

	// 加载配置
	configPath := "cmd/web/config.yaml"
	if err := config.LoadConfig(configPath); err != nil {
		configPath = "cmd/h5/config.yaml"
		if err := config.LoadConfig(configPath); err != nil {
			fmt.Printf("⚠️  无法加载配置，将创建空白迁移文件\n")
			createMigrationFile(name)
			return
		}
	}

	// 尝试初始化数据库连接（用于检查表是否存在）
	// 如果连接失败，仍然可以生成 CREATE TABLE SQL（假设表不存在）
	dbConnected := false
	var db *gorm.DB

	if err := core.Init(); err != nil {
		fmt.Printf("⚠️  无法连接数据库，将假设表不存在，直接生成 CREATE TABLE SQL\n")
		// 即使连接失败，也尝试使用一个最小配置来解析模型结构
		// 直接调用 generateSQLFromModel，它内部会处理
		generateSQLFromModel(name, "")
		return
	} else {
		defer core.Close()
		db = database.GetDB()
		if db != nil {
			dbConnected = true
		}
	}

	// 尝试解析模型获取表名
	stmt := &gorm.Statement{DB: db}
	parseErr := stmt.Parse(model)

	tableName := ""
	if parseErr == nil && stmt.Schema != nil && stmt.Schema.Table != "" {
		tableName = stmt.Schema.Table
	} else if tn, ok := model.(interface{ TableName() string }); ok {
		tableName = tn.TableName()
	}

	if tableName == "" {
		// 如果无法获取表名，尝试从模型类型推断
		if parseErr == nil && stmt.Schema != nil {
			// 使用模型类型名
			tableName = stmt.Schema.Table
		}
		if tableName == "" {
			fmt.Printf("⚠️  无法获取表名，将创建空白迁移文件\n")
			createMigrationFile(name)
			return
		}
	}

	// 如果数据库已连接，检查表是否存在
	if dbConnected {
		exists, err := database.TableExists(tableName)
		if err == nil {
			if exists {
				fmt.Printf("✅ 表 '%s' 已存在，使用 diff 生成 ALTER TABLE SQL\n", tableName)
				generateDiffFromModel(name, "")
				return
			} else {
				fmt.Printf("✅ 表 '%s' 不存在，使用 generate 生成 CREATE TABLE SQL\n", tableName)
				generateSQLFromModel(name, "")
				return
			}
		} else {
			fmt.Printf("⚠️  检查表是否存在失败，将假设表不存在并生成 CREATE TABLE SQL\n")
		}
	}

	// 数据库未连接或检查失败，直接生成 CREATE TABLE SQL
	fmt.Printf("✅ 假设表 '%s' 不存在，生成 CREATE TABLE SQL\n", tableName)
	generateSQLFromModel(name, "")
}

// createMigrationFile 创建新的空白迁移文件
func createMigrationFile(name string) {
	migrationsDir := "internal/infrastructure/database/migrations"

	// 获取下一个版本号
	version := getNextVersion(migrationsDir)

	filename := fmt.Sprintf("%s/%s_%s.sql", migrationsDir, version, name)
	content := `-- UP
-- TODO: 添加迁移 SQL

-- DOWN
-- TODO: 添加回滚 SQL
`

	if err := os.WriteFile(filename, []byte(content), 0644); err != nil {
		log.Fatalf("创建迁移文件失败: %v", err)
	}

	fmt.Printf("✅ 创建迁移文件: %s\n", filename)
}

// getNextVersion 获取下一个版本号
func getNextVersion(dir string) string {
	entries, err := os.ReadDir(dir)
	if err != nil {
		return "001"
	}

	maxVersion := 0
	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}
		name := entry.Name()
		if len(name) >= 3 {
			if version, err := strconv.Atoi(name[:3]); err == nil {
				if version > maxVersion {
					maxVersion = version
				}
			}
		}
	}

	return fmt.Sprintf("%03d", maxVersion+1)
}

// showStatusWithoutDB 显示迁移状态（不需要数据库连接也能显示文件列表）
func showStatusWithoutDB(configPathParam string) {
	migrationsDir := "internal/infrastructure/database/migrations"

	// 读取迁移文件列表
	entries, err := os.ReadDir(migrationsDir)
	if err != nil {
		fmt.Printf("❌ 无法读取迁移目录: %v\n", err)
		return
	}

	// 解析迁移文件
	var migrationFiles []struct {
		Version string
		Name    string
		Path    string
	}

	for _, entry := range entries {
		if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".sql") {
			continue
		}

		// 跳过占位文件
		if entry.Name() == ".gitkeep.sql" {
			continue
		}

		filename := strings.TrimSuffix(entry.Name(), ".sql")
		parts := strings.SplitN(filename, "_", 2)
		if len(parts) < 2 {
			continue
		}

		migrationFiles = append(migrationFiles, struct {
			Version string
			Name    string
			Path    string
		}{
			Version: parts[0],
			Name:    parts[1],
			Path:    entry.Name(),
		})
	}

	// 按版本号排序
	sort.Slice(migrationFiles, func(i, j int) bool {
		return migrationFiles[i].Version < migrationFiles[j].Version
	})

	if len(migrationFiles) == 0 {
		fmt.Println("\n📋 迁移文件列表:")
		fmt.Println("  暂无迁移文件")
		fmt.Println("\n💡 提示: 使用 'make migrate-create NAME=xxx' 创建迁移文件")
		return
	}

	fmt.Println("\n📋 迁移文件列表:")
	fmt.Println("版本号\t\t名称\t\t\t\t文件")
	fmt.Println(strings.Repeat("-", 80))

	for _, mf := range migrationFiles {
		fmt.Printf("%s\t\t%-30s\t%s\n", mf.Version, mf.Name, mf.Path)
	}

	// 尝试连接数据库获取执行状态
	fmt.Print("\n🔗 尝试连接数据库获取执行状态...")

	// 获取配置路径（优先使用参数，否则使用默认路径）
	var configPath string
	if configPathParam == "" || configPathParam == "./cmd/web/config.yaml" || configPathParam == "config/config.yaml" {
		configPath = "cmd/web/config.yaml"
		if _, err := os.Stat(configPath); os.IsNotExist(err) {
			configPath = "cmd/h5/config.yaml"
		}
	} else {
		configPath = configPathParam
	}

	fmt.Printf("\n📁 使用配置文件: %s\n", configPath)

	if err := config.LoadConfig(configPath); err != nil {
		fmt.Printf("⚠️  无法加载配置: %v\n", err)
		fmt.Println("\n💡 提示: 检查配置文件或数据库连接后，可以查看详细的执行状态")
		return
	}

	// 显示数据库配置信息（用于调试，密码用星号遮蔽）
	cfg := config.GetConfig()
	if cfg != nil && cfg.Database.Host != "" {
		passwordMask := "***"
		if cfg.Database.Password == "" {
			passwordMask = "(未设置)"
		} else {
			// 如果密码很短，显示相同数量的星号；否则显示3个星号
			if len(cfg.Database.Password) <= 3 {
				passwordMask = strings.Repeat("*", len(cfg.Database.Password))
			}
		}
		fmt.Printf("📊 数据库配置: %s:%s@%s:%d/%s\n", cfg.Database.Username, passwordMask, cfg.Database.Host, cfg.Database.Port, cfg.Database.Database)
	}

	// 临时修改 GORM 日志级别为 Silent（完全禁用日志输出）
	// 保存原始日志级别
	originalLevel := config.GetConfig().Log.Level
	// 创建一个临时的静默日志配置
	tempLevel := config.GetConfig().Log.Level
	config.GetConfig().Log.Level = "silent"

	// 尝试直接初始化数据库（使用静默日志）
	if err := database.InitMySQL(); err != nil {
		// 恢复原始日志级别
		config.GetConfig().Log.Level = originalLevel

		// 提取简化的错误信息
		errMsg := err.Error()
		// 移除 "failed to connect database: " 前缀
		if strings.HasPrefix(errMsg, "failed to connect database: ") {
			errMsg = strings.TrimPrefix(errMsg, "failed to connect database: ")
		}

		fmt.Printf(" 失败\n")
		fmt.Printf("⚠️  数据库连接失败: %s\n", errMsg)
		fmt.Println("\n💡 提示:")
		fmt.Printf("  - 检查数据库配置是否正确（配置文件: %s）\n", configPath)
		fmt.Println("  - 确保数据库服务正在运行")
		fmt.Println("  - 检查网络连接和防火墙设置")
		fmt.Println("  - 验证用户名、密码和主机地址")
		fmt.Println("\n📝 注意: 以上仅显示迁移文件列表，无法获取执行状态")
		return
	}

	// 恢复原始日志级别
	config.GetConfig().Log.Level = originalLevel
	_ = tempLevel // 避免未使用变量警告

	fmt.Printf(" 成功\n")
	defer func() {
		// 清理数据库连接
		db := database.GetDB()
		if db != nil {
			if sqlDB, err := db.DB(); err == nil {
				sqlDB.Close()
			}
		}
	}()

	// 获取执行状态
	status, err := database.GetMigrationStatus()
	if err != nil {
		fmt.Printf("⚠️  获取迁移状态失败: %v\n", err)
		return
	}

	// 构建已执行版本的映射
	appliedMap := make(map[string]string) // version -> appliedAt
	for _, s := range status {
		if s.Applied {
			appliedMap[s.Version] = s.AppliedAt
		}
	}

	fmt.Println("\n📊 迁移执行状态:")
	fmt.Println("版本号\t\t名称\t\t\t\t状态\t\t应用时间")
	fmt.Println(strings.Repeat("-", 80))

	for _, mf := range migrationFiles {
		statusStr := "⏳ 待执行"
		appliedAt := "-"
		if at, ok := appliedMap[mf.Version]; ok {
			statusStr = "✅ 已执行"
			appliedAt = at
		}
		fmt.Printf("%s\t\t%-30s\t%s\t\t%s\n", mf.Version, mf.Name, statusStr, appliedAt)
	}
}
